/* 
 * File:   main.cpp
 * Author: Connor Willison
 *
 * Created on March 4, 2012, 12:33 PM
 * Contains the WinMain api entry point
 * and window procedure.
 */

#include <windows.h>
#include <string.h>
#include <dinput.h>
#include <iostream>
#include <sstream>
#include "string_funcs.h"

using namespace std;

//prototypes

LRESULT CALLBACK WindowProcedure
(HWND hwnd, unsigned int message, WPARAM wParam, LPARAM lParam);

void readInput(LPDIRECTINPUTDEVICE8 gamepad);
string MakeString(stringstream* str, string pre, void* data);

BOOL CALLBACK EnumCallback(LPCDIDEVICEINSTANCE device, LPVOID self);

#define NUM_LINES 20
string text[NUM_LINES];
GUID gamepadGUID;

//WinMain - entry point for api

int WINAPI WinMain(HINSTANCE hInst, HINSTANCE hPrevInst,
        char * cmdParam, int cmdShow) {

    char className [] = "Basic Window";

    for (int i = 0; i < NUM_LINES; i++) {
        text[i] = "connor";
    }

    //first, create the window class
    WNDCLASS _class;
    _class.style = 0;
    _class.lpfnWndProc = WindowProcedure; // window procedure: mandatory
    _class.cbClsExtra = 0;
    _class.cbWndExtra = 0;
    _class.hInstance = hInst; // owner of the class: mandatory
    _class.hIcon = 0;
    _class.hCursor = ::LoadCursor(0, IDC_ARROW); // optional
    _class.hbrBackground = (HBRUSH) (COLOR_WINDOW + 1); // optional
    _class.lpszMenuName = 0;
    _class.lpszClassName = className; // mandatory

    //register the class
    ::RegisterClass(& _class);

    //now create the window
    HWND _hwnd;

    _hwnd = ::CreateWindow(
            className, // name of a registered window class
            "Gamepad Test", // window caption
            WS_OVERLAPPEDWINDOW, // window style
            CW_USEDEFAULT, // x position
            CW_USEDEFAULT, // y position
            CW_USEDEFAULT, // witdh
            CW_USEDEFAULT, // height
            0, // handle to parent window
            0, // handle to menu
            hInst, // application instance
            0); // window creation data

    //show the window
    ::ShowWindow(_hwnd, cmdShow);

    //update the window
    ::UpdateWindow(_hwnd);

    /* Initialize DirectInput */

    LPDIRECTINPUT8 dinput;
    LPDIRECTINPUTDEVICE8 gamepad;

    // create the DirectInput interface
    DirectInput8Create(hInst, // the handle to the application
            DIRECTINPUT_VERSION, // the compatible version
            IID_IDirectInput8, // the DirectInput interface version
            (void**) &dinput, // the pointer to the interface
            NULL); // COM stuff, so we'll set it to NULL

    //enumerate game controllers
    dinput->EnumDevices(
            DI8DEVCLASS_GAMECTRL,
            EnumCallback,
            0,
            DIEDFL_ALLDEVICES
            );

    // create the gamepad device
    dinput->CreateDevice(gamepadGUID, // the default keyboard ID being used
            &gamepad, // the pointer to the device interface
            NULL); // COM stuff, so we'll set it to NULL

    cout << "created the gamepad object..." << endl;

    ////    // set the data format to keyboard format
    //    if (gamepad->SetDataFormat(&c_dfDIJoystick) == DI_OK) {
    //        cout << "data format set..." << endl;
    //    } else {
    //        cout << "error setting data format..." << endl;
    //    }

    if (gamepad->SetDataFormat(&c_dfDIJoystick2) == DI_OK) {
        cout << "data format set..." << endl;
    } else {
        cout << "error setting data format..." << endl;
    }

    Sleep(3000);


    // set the control you will have over the keyboard
    gamepad->SetCooperativeLevel(_hwnd, DISCL_NONEXCLUSIVE | DISCL_FOREGROUND);

    cout << "cooperative level set..." << endl;
    
    

    DIJOYSTATE2 state;
    ZeroMemory(&state,sizeof(state));
    
    MSG msg;

    while (true) {
        //get messages from queue
        PeekMessage(&msg, NULL, 0, 0, PM_REMOVE);

        // If the message is WM_QUIT, exit the while loop
        if (&msg != NULL) {
            //stop program if needed
            if (msg.message == WM_QUIT) {

                //close direct input
                dinput->Release();

                break;
            }

            // Translate the message and dispatch it to WindowProc()
            TranslateMessage(&msg);
            DispatchMessage(&msg);
        }

        //read input from the gamepad

        gamepad->Acquire();

        gamepad->GetDeviceState(sizeof (DIJOYSTATE2), &state);

        //    LONG lX;
        //    LONG lY;
        //    LONG lZ;
        //    LONG lRx;
        //    LONG lRy;
        //    LONG lRz;
        //    LONG rglSlider[2];
        //    DWORD rgdwPOV[4];
        //    BYTE rgbButtons[32];

        //        cout << "lX: " << state.lX << endl;
        //        cout << "lY: " << state.lY << endl;
        //        cout << "lZ: " << state.lZ << endl;
        //        
        //        cout << "lRx: " << state.lRx << endl;
        //        cout << "lRy: " << state.lRy << endl;
        //        cout << "lRz: " << state.lRz << endl;
        //        
        //        cout << "slider 1: " << state.rglSlider[0] << endl;
        //        cout << "slider 2: " << state.rglSlider[1] << endl;

//                cout << "lX: " << state.lX << endl;
//                cout << "lY: " << state.lY << endl;
//                cout << "lZ: " << state.lZ << endl;
//        
//                cout << "lRx: " << state.lRx << endl;
//                cout << "lRy: " << state.lRy << endl;
//                cout << "lRz: " << state.lRz << endl;
//        
//                cout << "slider 1: " << state.rglSlider[0] << endl;
//                cout << "slider 2: " << state.rglSlider[1] << endl;
//        
//                cout << "lVX: " << state.lVX << endl;
//                cout << "lVY: " << state.lVY << endl;
//                cout << "lVZ: " << state.lVZ << endl;
//        
//                cout << "lVRx: " << state.lVRx << endl;
//                cout << "lVRy: " << state.lVRy << endl;
//                cout << "lVRz: " << state.lVRz << endl;
//        
//                cout << "slider v1: " << state.rglVSlider[0] << endl;
//                cout << "slider v2: " << state.rglVSlider[1] << endl;
//        
//                cout << "lAX: " << state.lAX << endl;
//                cout << "lAY: " << state.lAY << endl;
//                cout << "lAZ: " << state.lAZ << endl;
//        
//                cout << "lARx: " << state.lARx << endl;
//                cout << "lARy: " << state.lARy << endl;
//                cout << "lARz: " << state.lARz << endl;
//        
//                cout << "slider a1: " << state.rglASlider[0] << endl;
//                cout << "slider a2: " << state.rglASlider[1] << endl;
//        
//                cout << "lFX: " << state.lFX << endl;
//                cout << "lFY: " << state.lFY << endl;
//                cout << "lFZ: " << state.lFZ << endl;
//        
//                cout << "lFRx: " << state.lFRx << endl;
//                cout << "lFRy: " << state.lFRy << endl;
//                cout << "lFRz: " << state.lFRz << endl;
//        
//                cout << "slider f1: " << state.rglFSlider[0] << endl;
//                cout << "slider f2: " << state.rglFSlider[1] << endl;

        //        text[0] = "lX: " + to_String<long>(state.lX);
        //        text[1] = "lY: " + to_String<long>(state.lY);
        //        text[2] = "lZ: " + to_String<long>(state.lZ);
        //
        //        text[3] = "lRx: " + to_String<long>(state.lRx);
        //        text[4] = "lRy: " + to_String<long>(state.lRy);
        //        text[5] = "lRz: " + to_String<long>(state.lRz);

        ::UpdateWindow(_hwnd);

        ::Sleep(20);

    }

    return msg.wParam;
}

// Window Procedure called by Windows

LRESULT CALLBACK WindowProcedure
(HWND hwnd, unsigned int message, WPARAM wParam, LPARAM lParam) {
    switch (message) {
        case WM_LBUTTONDOWN:
        {
            ::MessageBox(hwnd, "You clicked the mouse.", "Notification", MB_OK);
            break;
        }
        case WM_PAINT:
        {
            //show some text
            PAINTSTRUCT ps; //paint structure
            HDC hdc; //device context

            //initialize hdc and paintstruct
            hdc = ::BeginPaint(hwnd, &ps);

            //draw text
            for (int i = 0; i < NUM_LINES; i++) {
                ::TextOut(hdc, 10, 5 + i * 25, text[i].c_str(), text[i].length());
                cout << "drew line " << i << endl;
            }

            //free hdc
            ::DeleteDC(hdc);

            //free paintstruct
            ::EndPaint(hwnd, &ps);

            break;
        }
        case WM_DESTROY:
        {
            ::PostQuitMessage(0);
            return 0;
        }
        default:
        {
            return ::DefWindowProc(hwnd, message, wParam, lParam);
        }

    }
}

BOOL CALLBACK EnumCallback(LPCDIDEVICEINSTANCE device, LPVOID self) {
    cout << "found a gamepad: " << device->tszProductName << " : " << device->tszInstanceName << endl;
    gamepadGUID = device->guidInstance;

    //stop enumeration
    return DIENUM_STOP;
}




